package my.design.enjoy;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author zp
 * @version 1.0
 * @description: 充电宝箱子：享元工厂
 * 享元模式
 * 享元模式的定义过于官方，说白了通过池技术来保存大量相似或相同（指同一类型或继承同一父类）的对象，
 * 暴露其共同的属性隐藏其私有属性来进行反复的使用。
 *
 * 在享元模式中可以共享出来的部分称为内部状态，而其中不被共享的部分称为外部状态，
 * 这样使得这一堆对象即可以使用共同的方法，也可以强制转型后使用自己的特有方法。
 * JKD 当中 Integer 使用了IntegerCache 保存了-128到127当中的数据
 * 如果使用Integer.valueOf获取的值是在-128到127这个范围当中 就是使用的享元模式 返回的是缓存的对象
 *
 * @date 2022/10/15 15:32
 */
public class PowerBankBox {

    private static final Map<Integer, BasePowerBankFlyWeight> powerBankPool = new HashMap<>();

    private static Integer powerBankNum = 1;

    static {

        // 初始化时创建两个充电宝放到充电箱中
        PowerBank powerBank = new PowerBank(powerBankNum++, "罗马仕");
        PowerBank powerBank2 = new PowerBank(powerBankNum++, "小米");
        powerBankPool.put(powerBank.getId(), powerBank);
        powerBankPool.put(powerBank2.getId(), powerBank2);
    }

    /**
     * 添加一个充电宝到充电宝箱中
     */
    public void addPowerBank(BasePowerBankFlyWeight powerBank) {
        powerBankPool.put(powerBankNum++, powerBank);
    }

    /**
     * 取出充电宝
     */
    public static BasePowerBankFlyWeight usePowerBank(Integer num) {

        // 首先查找指定的充电宝
        BasePowerBankFlyWeight powerBank = powerBankPool.get(num);

        // 如果找不到指定编号的充电宝或者指定编号充电宝正在使用中，则随机返回一个充电宝
        if (Objects.isNull(powerBank) || powerBank.inUse) {

            // 遍历连接迟中所有充电宝
            for (BasePowerBankFlyWeight p : powerBankPool.values()) {

                // 如果某个充电宝未在使用，则返回这个充电宝
                if (!p.inUse) {
                    return p;
                }
            }

            // 循环到最后都没有空闲的充电宝，则返回null
            return null;
        }

        // 如果找到了指定编号的充电宝且没有在使用，直接返回指定充电宝
        return powerBank;
    }

}

